#include<bits/stdc++.h>
using namespace std;
typedef double db;
typedef long long ll;
//typedef long double db;
typedef long double ldb;
const int N=200010;
const db pi=acos(-1.0);
const db eps=1e-12;
const db inf=1e18;
/* Geometry_2D by Bakabamboo
 * 注意事项：
 * 1）比较时使用eps
 * 2）请不要暴力除出来斜率
 * 3）实数二分不要根据精度，要根据次数
 * 4）本人下标从1开始
 * 5）不要cin/cout，不要scanf一个longdouble
 * 6）有些时候请考虑把db换成ll
 * 下面是点/直线/矢量/圆的一些运算，具体包括：
 * 1）两点距离，点线距离，点到圆切点距离，切点（还没空写），线线交点（若不交，返回{inf，线线距离}）
 * 2）矢量的点积(p_mul)、叉积(c_mul)，极角排序(theta_sort)
 * 3）凸包，使用c_hull
 * 4）半平面交，使用hf_plane
 * 5）旋转卡壳，使用rotate
 * 6）最小圆覆盖，使用cir_cover
 * 7）由于时间与能力有限，这里没有线段运算，更没有动态维护凸包QAQ
 */
#define point vec
//vec
struct vec{
    db x,y;
    int dim()const{
        if(x>0&&y>=0)return 1;
        if(x<=0&&y>0)return 2;
        if(y<=0&&x<0)return 3;
        if(y<0&&x>=0)return 4;
    }
};
bool operator<(vec a,vec b){return (a.x==b.x)?a.y<b.y:a.x<b.x;}
vec operator+(vec a,vec b){return vec{a.x+b.x,a.y+b.y};}
vec operator-(vec a,vec b){return vec{a.x-b.x,a.y-b.y};}
vec operator*(db  a,vec b){return vec{a*b.x,a*b.y};}
vec operator*(vec a,db  b){return vec{a.x*b,a.y*b};}
vec operator/(vec a,db  b){return vec{a.x/b,a.y/b};}
inline db p_mul(vec a,vec b){return a.x*b.x+a.y*b.y;}
inline db c_mul(vec a,vec b){return a.x*b.y-a.y*b.x;}
inline bool chk(vec a,vec b){return fabs(c_mul(a,b))<eps;}
inline bool chkr(vec a,vec b){return c_mul(a,b)<-eps;}//b在a右侧
inline bool chkl(vec a,vec b){return c_mul(a,b)>eps;}//b在a左侧
inline db len(point a){return sqrt(p_mul(a,a));}
inline db len2(point a){return p_mul(a,a);}
//直线与点
struct line{
    point a;vec k;
    int dim()const{
        if(k.x>0&&k.y>=0)return 1;
        if(k.x<=0&&k.y>0)return 2;
        if(k.y<=0&&k.x<0)return 3;
        if(k.y<0&&k.x>=0)return 4;
    }
};//点向式
void theta_sort(vec *a,int n){//极角序 向量
    sort(a+1,a+n+1,[&](vec a,vec b){return (a.dim()==b.dim())?chkl(a,b):a.dim()<b.dim();});
}
void theta_sort(line *a,int n){//极角序 线
    sort(a+1,a+n+1,[&](line a,line b){return (a.dim()==b.dim())?chkl(a.k,b.k):a.dim()<b.dim();});
}
inline db dis(point a,point b){return len(b-a);}
inline db dis2(point a,point b){return len2(b-a);}
inline db dis(point a,line b){return (c_mul(a-b.a,b.k))/len(b.k);}//【带符号】点线距离
point isc(line a,line b){//交点
    if(fabs(c_mul(a.k,b.k))<eps){return point{inf,dis(a.a,b)};}
    db t=c_mul(b.k,a.a-b.a)/c_mul(a.k,b.k);
    return a.a+a.k*t;
}
//线段
struct seg{point a,b;};
bool isc(seg a,seg b){//它们相交吗？
    return c_mul(a.b-a.a,b.a-a.a)*c_mul(a.b-a.a,b.b-a.a)<-eps&&c_mul(b.b-b.a,a.a-b.a)*c_mul(b.b-b.a,a.b-b.a)<-eps;
};
//注意顺时针还是逆时针
line trans(seg a){return {a.a,a.b-a.a};}//两点变点向
line trans(point a,point b){return {a,b-a};}
int tot;
point s[N];
void c_hull(point *a,int n){//把一个点集变成凸包
    if(n<2)return;
    tot=0;
    sort(a+1,a+n+1);
    s[++tot]=a[1];
    for(int i=2;i<=n;i++){
        while(tot>=2&&chkr(s[tot]-s[tot-1],a[i]-s[tot-1]))tot--;
        s[++tot]=a[i];
    }int tmp=tot;
    for(int i=n-1;i>=1;i--){
        while(tot>tmp&&chkr(s[tot]-s[tot-1],a[i]-s[tot-1]))tot--;
        s[++tot]=a[i];
    }
    for(int i=1;i<=tot;i++)a[i]=s[i];
    for(int i=tot+1;i<=n;i++)a[i]={0,0};
}
db plg_area(point *a,int n){//多边形面积
    db ans=0;
    for(int i=2;i<n;i++)ans+=c_mul(a[i]-a[1],a[i+1]-a[1]);
    return ans/2;
}
db plg_len(point *a,int n){//多边形周长
    db ans=0;
    for(int i=1;i<n;i++)ans+=dis(a[i],a[i+1]);
    return ans+dis(a[1],a[n]);
}
bool hf_plane(line *a,int n,point *b){//半平面交
    theta_sort(a,n);
    int l=1,r=1;
    vector<line>q(n);
    q[l]=a[1];
    for(int i=2;i<=n;i++){
        while(r>l&&chkr(a[i].k,b[r]-a[i].a))r--;
        while(r>l&&chkr(a[i].k,b[l+1]-a[i].a))l++;
        q[++r]=a[i];
        if(chk(q[r].k,q[r-1].k)){
            if(chkr(q[r].k,q[r-1].a-q[r].a)&&p_mul(q[r].k,q[l].k)<-eps){return 0;}
            r--;if(chkr(a[i].k,q[r].a-a[i].a))q[r]=a[i];
        }
        if(r>l)b[r]=isc(q[r],q[r-1]);
    }
    while(l<r&&chkr(q[l].k,b[r]-q[l].a))r--;
    if(r-l<2){return 0;}
    b[l]=isc(q[l],q[r]);
    for(int i=1;i<=r-l+1;i++)b[i]=b[l+i-1];
    tot=r-l+1;
    return 1;
}
db rotate(point *a,int n){//旋转卡壳算法
    if(n==2)return dis2(a[1],a[2]);
    int op=2;db ans=0;
    for(int i=1;i<=n;i++){
        while(c_mul(a[i]-a[op],a[i+1]-a[i])-c_mul(a[i]-a[op+1],a[i+1]-a[i])<-eps)op=(op+1)%n;
        ans=max({ans,dis2(a[i],a[op]),dis2(a[i+1],a[op])});
    }
    return ans;
}
//圆
struct circle{
    point a;db r;
    db s()const{return pi*r*r;}
    db d()const{return 2.0*pi*r;}
};
db dis(point a,circle c){
    db m=dis(c.a,a)-c.r*c.r;
    if(fabs(m)<eps)return -1;
    return sqrt(fabs(m));
}
circle cir_2(point a,point b){
    return{(a+b)/2,dis(a,b)/2};
}
circle cir_3(point a,point b,point c){
    if(chk(b-a,c-a))return {inf,inf,inf};
    vec B=c-a,C=b-a;
    db lb=len2(B),lc=len2(C);
    db d=c_mul(B,C)*2;
    vec l={C.y*lb-B.y*lc,B.x*lc-C.x*lb};
    return{a+l/d, fabs(len(l)/d)};
}
circle cir_cover(point *a,int n){
    db r2=0;point o{0,0};
    random_shuffle(a+1,a+n+1);
    for(int i=1; i<=n; i++){
        if(dis(a[i],o)>r2+eps){
            o=a[i],r2=0;
            for(int j=1;j<i;j++){
                if(dis(a[j],o)>r2+eps){
                    o=(a[i]+a[j])/2,r2=dis(a[j],o);
                    for(int k=1;k<j;k++){
                        if(dis(a[k],o)>r2+eps)o=cir_3(a[k],a[i],a[j]).a,r2=dis(a[k],o);
                    }
                }
            }
        }
    }
    return{o,r2};
}
//自适应simpson积分
/*
db a,b,c,d,l,r;
db sim(db x) {return (c*x+d)/(a*x+b);}
db pson(db l,db r) {return (r-l)*(sim(l)+sim(r)+4*sim((l+r)/2))/6;}
double simpson(db l,db r,db ans){
    db mid=(l+r)/2,ans1=pson(l,mid),ans2=pson(mid,r);
    if(fabs(ans1+ans2-ans)<=eps)return ans;
    return simpson(l,mid,ans1)+simpson(mid,r,ans2);
}
 */
//line l[N]
point a[N];//Point or Polygon or Vector
//point b[N];
int main(){
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        db x,y;
        scanf("%lf%lf",&x,&y);
        a[i]={x,y};
    }
    c_hull(a,n);
    printf("%.2lf",plg_len(a,tot));
    return 0;
}
